From 25de1f6920591b8240649028fc3fd755140f29f6 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 14 Jul 2005 09:05:22 +0000 Subject: [PATCH] Allow arch-specific defaults to be specified for ns16550 uart configuration. Based on a patch from Hollis Blanchard at IBM. Signed-off-by: Keir Fraser --- xen/arch/ia64/pcdp.c | 10 ++-- xen/arch/ia64/xensetup.c | 8 ++- xen/arch/x86/setup.c | 12 +++- xen/drivers/char/ns16550.c | 110 ++++++++++++++++++++++--------------- xen/include/xen/serial.h | 10 +++- 5 files changed, 98 insertions(+), 52 deletions(-) diff --git a/xen/arch/ia64/pcdp.c b/xen/arch/ia64/pcdp.c index 469047a69d..cab5eb2ff5 100644 --- a/xen/arch/ia64/pcdp.c +++ b/xen/arch/ia64/pcdp.c @@ -24,11 +24,11 @@ static int __init setup_serial_console(struct pcdp_uart *uart) { #ifdef XEN - extern char opt_com1[1]; - if (opt_com1[0]) return 0; - sprintf(&opt_com1[0], "%lu,%dn1,0x%lx,9", - uart->baud, uart->bits ? uart->bits : 8, - uart->addr.address); + extern struct ns16550_defaults ns16550_com1; + ns16550_com1.baud = uart->baud; + ns16550_com1.io_base = uart->addr.address; + if (uart->bits) + ns16550_com1.data_bits = uart->bits; return 0; #else #ifdef CONFIG_SERIAL_8250_CONSOLE diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c index d95eebfc9f..aa86c6c651 100644 --- a/xen/arch/ia64/xensetup.c +++ b/xen/arch/ia64/xensetup.c @@ -131,6 +131,12 @@ void early_cmdline_parse(char **cmdline_p) return; } +struct ns16550_defaults ns16550_com1 = { + .data_bits = 8, + .parity = 'n', + .stop_bits = 1 +}; + void start_kernel(void) { unsigned char *cmdline; @@ -153,7 +159,7 @@ void start_kernel(void) /* We initialise the serial devices very early so we can get debugging. */ if (running_on_sim) hpsim_serial_init(); - else ns16550_init(); + else ns16550_init(0, &ns16550_com1); serial_init_preirq(); init_console(); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index e74adf86e8..10c525c989 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -247,6 +247,11 @@ void __init __start_xen(multiboot_info_t *mbi) unsigned long initial_images_start, initial_images_end; struct e820entry e820_raw[E820MAX]; int i, e820_raw_nr = 0, bytes = 0; + struct ns16550_defaults ns16550 = { + .data_bits = 8, + .parity = 'n', + .stop_bits = 1 + }; /* Parse the command-line options. */ if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) ) @@ -259,7 +264,12 @@ void __init __start_xen(multiboot_info_t *mbi) smp_prepare_boot_cpu(); /* We initialise the serial devices very early so we can get debugging. */ - ns16550_init(); + ns16550.io_base = 0x3f8; + ns16550.irq = 4; + ns16550_init(0, &ns16550); + ns16550.io_base = 0x2f8; + ns16550.irq = 3; + ns16550_init(1, &ns16550); serial_init_preirq(); init_console(); diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c index 680a6ef1bc..3a08bdb5cf 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -16,7 +16,7 @@ #include /* Config serial port with a string ,DPS,,. */ -char opt_com1[30] = "", opt_com2[30] = ""; +static char opt_com1[30] = "", opt_com2[30] = ""; string_param("com1", opt_com1); string_param("com2", opt_com2); @@ -25,10 +25,7 @@ static struct ns16550 { unsigned long io_base; /* I/O port or memory-mapped I/O address. */ char *remapped_io_base; /* Remapped virtual address of mmap I/O. */ struct irqaction irqaction; -} ns16550_com[2] = { - { 0, 0, 0, 0, 4, 0x3f8 }, - { 0, 0, 0, 0, 3, 0x2f8 } -}; +} ns16550_com[2] = { { 0 } }; /* Register offsets */ #define RBR 0x00 /* receive buffer */ @@ -157,9 +154,12 @@ static void ns16550_init_preirq(struct serial_port *port) ns_write_reg(uart, IER, 0); /* Line control and baud-rate generator. */ - ns_write_reg(uart, LCR, lcr | LCR_DLAB); - ns_write_reg(uart, DLL, 115200/uart->baud); /* baud lo */ - ns_write_reg(uart, DLM, 0); /* baud hi */ + if ( uart->baud != 0 ) + { + ns_write_reg(uart, LCR, lcr | LCR_DLAB); + ns_write_reg(uart, DLL, 115200/uart->baud); /* baud lo */ + ns_write_reg(uart, DLM, 0); /* baud hi */ + } ns_write_reg(uart, LCR, lcr); /* parity, data, stop */ /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */ @@ -178,6 +178,9 @@ static void ns16550_init_postirq(struct serial_port *port) struct ns16550 *uart = port->uart; int rc; + if ( uart->irq <= 0 ) + return; + serial_async_transmit(port); uart->irqaction.handler = ns16550_interrupt; @@ -213,6 +216,24 @@ static struct uart_driver ns16550_driver = { .getc = ns16550_getc }; +static int parse_parity_char(int c) +{ + switch ( c ) + { + case 'n': + return PARITY_NONE; + case 'o': + return PARITY_ODD; + case 'e': + return PARITY_EVEN; + case 'm': + return PARITY_MARK; + case 's': + return PARITY_SPACE; + } + return 0; +} + #define PARSE_ERR(_f, _a...) \ do { \ printk( "ERROR: " _f "\n" , ## _a ); \ @@ -221,49 +242,24 @@ static struct uart_driver ns16550_driver = { static void ns16550_parse_port_config(struct ns16550 *uart, char *conf) { - if ( *conf == '\0' ) - return; + int baud; - uart->baud = simple_strtol(conf, &conf, 10); - if ( (uart->baud < 1200) || (uart->baud > 115200) ) - PARSE_ERR("Baud rate %d outside supported range.", uart->baud); + if ( (conf == NULL) || (*conf == '\0') ) + goto config_parsed; - if ( *conf != ',' ) - PARSE_ERR("Missing data/parity/stop specifiers."); + if ( (baud = simple_strtol(conf, &conf, 10)) != 0 ) + uart->baud = baud; + if ( *conf != ',' ) + goto config_parsed; conf++; uart->data_bits = simple_strtol(conf, &conf, 10); - if ( (uart->data_bits < 5) || (uart->data_bits > 8) ) - PARSE_ERR("%d data bits are unsupported.", uart->data_bits); - - switch ( *conf ) - { - case 'n': - uart->parity = PARITY_NONE; - break; - case 'o': - uart->parity = PARITY_ODD; - break; - case 'e': - uart->parity = PARITY_EVEN; - break; - case 'm': - uart->parity = PARITY_MARK; - break; - case 's': - uart->parity = PARITY_SPACE; - break; - - default: - PARSE_ERR("Invalid parity specifier '%c'.", *conf); - } + uart->parity = parse_parity_char(*conf); conf++; uart->stop_bits = simple_strtol(conf, &conf, 10); - if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) ) - PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits); if ( *conf == ',' ) { @@ -277,13 +273,39 @@ static void ns16550_parse_port_config(struct ns16550 *uart, char *conf) } } + config_parsed: + /* Sanity checks. */ + if ( (uart->baud != 0) && ((uart->baud < 1200) || (uart->baud > 115200)) ) + PARSE_ERR("Baud rate %d outside supported range.", uart->baud); + if ( (uart->data_bits < 5) || (uart->data_bits > 8) ) + PARSE_ERR("%d data bits are unsupported.", uart->data_bits); + if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) ) + PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits); + if ( uart->io_base == 0 ) + PARSE_ERR("I/O base address must be specified."); + + /* Register with generic serial driver. */ serial_register_uart(uart - ns16550_com, &ns16550_driver, uart); } -void ns16550_init(void) +void ns16550_init(int index, struct ns16550_defaults *defaults) { - ns16550_parse_port_config(&ns16550_com[0], opt_com1); - ns16550_parse_port_config(&ns16550_com[1], opt_com2); + struct ns16550 *uart = &ns16550_com[index]; + + if ( (index < 0) || (index > 1) ) + return; + + if ( defaults != NULL ) + { + uart->baud = defaults->baud; + uart->data_bits = defaults->data_bits; + uart->parity = parse_parity_char(defaults->parity); + uart->stop_bits = defaults->stop_bits; + uart->irq = defaults->irq; + uart->io_base = defaults->io_base; + } + + ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2); } /* diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 8d5f246ab2..e36e087cef 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -113,7 +113,15 @@ void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs); /* * Initialisers for individual uart drivers. */ -void ns16550_init(void); +struct ns16550_defaults { + int baud; /* default baud rate; 0 == pre-configured */ + int data_bits; /* default data bits (5, 6, 7 or 8) */ + int parity; /* default parity (n, o, e, m or s) */ + int stop_bits; /* default stop bits (1 or 2) */ + int irq; /* default irq */ + unsigned long io_base; /* default io_base address */ +}; +void ns16550_init(int index, struct ns16550_defaults *defaults); #endif /* __XEN_SERIAL_H__ */ -- 2.30.2